#include <boot/mbr.h>

.text

    .global dragon

    .code16
.org 0x5a
dragon:
    pushw $0
    pushw $my_start
    retf
my_start:
    movw %cs, %ax
    movw %ax, %ds
    movw %ax, %es
    movw %ax, %ss
    movw $MBR_BASE_ADDR, %sp
    movw $(MBR_BASE_ADDR+DRIVE_FLAG_OFF), %bp
    movb %dl, (%bp) # 保存驱动器编号（dl）

    pushw   %bp                         # 保存基指针
    movb    $0, 0x1(%bp)               # 扩展标志此处设置为不支持-0.

    # 检查是否支持 INT 13 扩展。如果清除了 CF，
    # 则 BX 更改为 0xAA55，并且设置了 CX 中的最低位，则支持它们。


    movb    $0x41, %ah                     # Set AH.
    movw    $0x55AA, %bx                   # 将BX设置成魔数
    int     $0x13                          # 调用0x13号中断
    popw    %bp                            # 恢复BP
    jb      after_int13_extensions_check   # 无符号小于则跳转（jb:CF=1）
    cmpw    $0xAA55, %bx                   # 查看BX是否等于0xAA55.
    jnz     after_int13_extensions_check   # 不相等则跳转
    test    $0x0001, %cx                   # 查看CX最低位是否被置1
    jz      after_int13_extensions_check   # 为0则跳转
    incb    0x1(%bp)                       # 扩展标志此处设置为支持-1

after_int13_extensions_check:
    cmpb    $0, 0x1(%bp)                   # 检查扩展标志
    jz      extend_not_support_error       # 如果不支持则失败

3:
# INT 13h AH:42h ds:si(硬盘地址包大小[1 byte],保留值[1 byte],传输的扇区数[2 byte])
    pushl   $0                                              # 起始扇区偏移高32位
    pushl   $LOAD_START_SECTOR                              # 起始扇区偏移低32位
    pushl   $((LOAD_CS_BASE<<4)+LOAD_ADDR_OFFSET)           # 缓冲区偏移（cs:offset）
    pushw   $LOAD_SECTOR_NUM                                # 读取扇区数
    pushw   $0x0010                                         # 包大小和保留字
    movb    $0x42, %ah                                      # Function 0x42, extended read.
    movb    (%bp), %dl                                      # 驱动器编号.
    movw    %sp, %si                                        # SI points to the disk packet address.

    int $0x13

    #
    # 检查中断返回值, CF = 0, AH = 0 成功;CF = 1, AH = 错误码
    #

    # LAHF（加载状态标志位到 AH）指令将 EFLAGS 寄存器的低字节复制到 AH。
    # 被复制的标志位包括：符号标志位、零标志位、辅助进位标志位、奇偶标志位和进位标志位(CF)，主要保存CF
    lahf                                # add指令会影响CF标志位
    addw    $0x10, %sp                  # 将扩展读参数弹出栈
    sahf                                # 恢复标志寄存器
    jmp     after_disk_read             # 跳转
    

after_disk_read:
    jnb     read_success           # 标志位CF=0（调用0x13中断正常）,则跳转
    movw    $read_failure_message, %si
    jmp     print_string_and_die
    

read_success:
    cli                    # 关中断
    push %ds                # save real mode

    lgdt (gdtinfo)         # load gdt register

    movl  %cr0, %eax          # switch to pmode by
    or $0x1, %al                # set pmode bit
    movl %eax, %cr0
    jmp $0x8, $pmode

pmode:
    mov  $0x10, %bx          # select descriptor 2
    mov  %bx, %ds            # 10h = 10000b

    and $0xFE, %al            # back to realmode
    movl %eax, %cr0          # by toggling bit again
    jmp $0x0, $unreal

unreal:
    pop %ds                 # get back old segment
    sti

    jmp bootloader_start

extend_not_support_error:
    movw    $not_support_message, %si
    jmp     print_string_and_die
print_string_and_die:
    cld                                 # 将拷贝字符串方向设置为向前
    lodsb                               # 将%si赋值给%al,并加1
    cmp     $0, %al                     # 判断是否结束字符'\0'
    jz      die                         # 打印完进入死循环
    movw    $0x0007, %bx                # 打印黑底白字
    movb    $0x0E, %ah                  # 打印字符子例程
    int     $0x10                       # 调用中断
    jmp     print_string_and_die        # 循环打印更多字符

    #
    # This is the end of the line.
    #

die:
    hlt                                 # Stop.
    jmp     die                         # Die again forever.

not_support_message:
    .asciz "BIOS 13h not support extended read"
read_failure_message:
    .asciz "Bootloader code Read Error" 

gdt:        .dc.l 0,0        # entry 0 is always unused
codedesc:   .dc.b 0xff, 0xff, 0, 0, 0, 0b10011010, 0b00000000, 0
flatdesc:   .dc.b 0xff, 0xff, 0, 0, 0, 0b10010010, 0b11001111, 0

.equiv GdtLen, .-gdt
gdtinfo:
    .dc.w GdtLen-1   #last byte in table
    .dc.l  gdt              #start of table
# 至此不会超过 0x1b8-0x5a 字节
    .fill 512-(.-dragon)-0x5a, 1, 0

# 在dd拷贝中不会拷贝这里，只做跳转的地址用
bootloader_start:
